package com.tsfyun.scm.service.impl.system;

import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.constant.CacheConstant;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.OrderItem;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.system.ExpenseSubjectDTO;
import com.tsfyun.scm.entity.system.ExpenseSubject;
import com.tsfyun.scm.mapper.system.ExpenseSubjectMapper;
import com.tsfyun.scm.service.system.IExpenseSubjectService;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.common.base.vo.ExpenseSubjectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 费用会计科目服务实现类
 */
@Slf4j
@Service
public class ExpenseSubjectServiceImpl extends ServiceImpl<ExpenseSubject> implements IExpenseSubjectService {

    @Autowired
    private OrikaBeanMapper beanMapper;

    @Autowired
    private ExpenseSubjectMapper expenseSubjectMapper;

    @CacheEvict(value = CacheConstant.EXPENSESUBJECT_LIST,allEntries = true,beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(ExpenseSubjectDTO dto) {
        ExpenseSubject expenseSubject = beanMapper.map(dto,ExpenseSubject.class);
        try {
            super.saveNonNull(expenseSubject);
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("uni_name")) {
                throw new ServiceException(String.format("已经存在名称为：%s的费用科目",dto.getName()));
            } else {
                throw new ServiceException("费用科目编码已经存在");
            }
        }
    }

    @CacheEvict(value = CacheConstant.EXPENSESUBJECT_LIST,allEntries = true,beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(ExpenseSubjectDTO dto) {
        ExpenseSubject expenseSubject = super.getById(dto.getPreId());
        TsfPreconditions.checkArgument(Objects.nonNull(expenseSubject),new ServiceException("费用科目信息不存在"));
        TsfPreconditions.checkArgument(Objects.equals(expenseSubject.getLocking(),Boolean.FALSE),new ServiceException("费用科目已被锁定禁止修改"));
        try {
            expenseSubjectMapper.update(dto, SecurityUtil.getCurrentPersonIdAndName());
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("uni_name")) {
                throw new ServiceException(String.format("已经存在名称为：%s的费用科目",dto.getName()));
            } else {
                throw new ServiceException("费用科目编码已经存在");
            }
        }
    }

    @Override
    public PageInfo<ExpenseSubject> page(ExpenseSubjectDTO dto) {
        TsfWeekendSqls sqls = TsfWeekendSqls.<ExpenseSubject>custom()
                .andLike(true,ExpenseSubject::getName,dto.getName())
                .andLike(true,ExpenseSubject::getId,dto.getId())
                .andEqualTo(true,ExpenseSubject::getDisabled,dto.getDisabled());
        PageInfo<ExpenseSubject> pageInfo = super.pageList(dto.getPage(),dto.getLimit(),sqls, Lists.newArrayList(OrderItem.asc("id")));
        return pageInfo;
    }

    @CacheEvict(value = CacheConstant.EXPENSESUBJECT_LIST,allEntries = true,beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String id) {
        ExpenseSubject expenseSubject = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(expenseSubject),new ServiceException("费用科目信息不存在"));
        //锁定的不允许删除
        TsfPreconditions.checkArgument(Objects.equals(expenseSubject.getLocking(),Boolean.FALSE),new ServiceException("费用科目已被锁定，不允许删除"));
        try {
            super.removeById(id);
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("当前费用科目存在关联性数据，不允许删除");
        }
    }

    @Override
    public List<ExpenseSubjectVO> allList(ExpenseSubjectDTO dto) {
        return  expenseSubjectMapper.list(dto);
    }

    @CacheEvict(value = CacheConstant.EXPENSESUBJECT_LIST,allEntries = true,beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDisabled(String id, Boolean disabled) {
        ExpenseSubject expenseSubject = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(expenseSubject),new ServiceException("费用科目信息不存在"));
        TsfPreconditions.checkArgument(!expenseSubject.getLocking(),new ServiceException("费用科目已被锁定禁止修改"));

        ExpenseSubject update = new ExpenseSubject();
        update.setDisabled(disabled);
        expenseSubjectMapper.updateByExampleSelective(update, Example.builder(ExpenseSubject.class).where(
                WeekendSqls.<ExpenseSubject>custom().andEqualTo(ExpenseSubject::getId, id)).build()
        );
    }

    @Override
    public ExpenseSubjectVO detail(String id) {
        ExpenseSubject expenseSubject = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(expenseSubject),new ServiceException("费用科目信息不存在"));
        return beanMapper.map(expenseSubject,ExpenseSubjectVO.class);
    }


    @Cacheable(value = CacheConstant.EXPENSESUBJECT_LIST)
    public List<ExpenseSubject> allActive() {
        List<ExpenseSubject> dataList = super.list().stream().filter(r->!Objects.equals(r.getDisabled(),Boolean.TRUE)).collect(Collectors.toList());
        return dataList;
    }

    @CacheEvict(value = CacheConstant.EXPENSESUBJECT_LIST,allEntries = true,beforeInvocation = true)
    @Override
    public void clear() {
        log.info("清除费用科目缓存成功");
    }
}
